﻿using System;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Threading;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using WcfCGServicesHost.Properties;

namespace WcfCGServicesHost
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Fields

        private bool isClosing = false;
        private System.Windows.Forms.NotifyIcon notifyIcon = null;
        private WindowState storedWindowState = WindowState.Normal;
        private ServiceHost wcgServiceHost = null;
        private CallLogger callLogger = null;
        private SynchronizationContext context = null;

        private const string IdleImageUri = "pack://application:,,,/WcfCGServicesHost;component/Resources/idle.png";
        private const string ProgressImageUri = "pack://application:,,,/WcfCGServicesHost;component/Resources/progress.png";

        #endregion

        #region Constructors

        public MainWindow()
        {
            InitializeComponent();

            this.btnExit.Click += new RoutedEventHandler(this.btnExit_Click);
            this.StateChanged += new EventHandler(this.OnStateChanged);
            this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(this.OnIsVisibleChanged);

            this.context = SynchronizationContext.Current;

            this.CreateNotifyIcon();
            this.StartServices();
        }

        #endregion

        #region Overrides

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (!this.isClosing)
            {
                e.Cancel = true;
                this.WindowState = System.Windows.WindowState.Minimized;
            }
            else
            {
                this.StopServices();
                this.ShowTrayIcon(false);
                this.notifyIcon.Dispose();
                this.notifyIcon = null;
            }
        }

        #endregion

        #region Methods (Private)

        private void CreateNotifyIcon()
        {
            this.notifyIcon = new System.Windows.Forms.NotifyIcon();

            this.notifyIcon.Text = this.Title;
            this.notifyIcon.Icon = new System.Drawing.Icon(
                Assembly.GetExecutingAssembly().GetManifestResourceStream("WcfCGServicesHost.appIconIdle.ico"));

            this.notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu();
            System.Windows.Forms.MenuItem openItem = new System.Windows.Forms.MenuItem(
                "Open",
                this.OnContextMenuOpen);
            openItem.Index = 0;
            openItem.DefaultItem = true;
            System.Windows.Forms.MenuItem exitItem = new System.Windows.Forms.MenuItem(
                "Exit",
                this.OnContextMenuExit);
            exitItem.Index = 1;
            this.notifyIcon.ContextMenu.MenuItems.Add(openItem);
            this.notifyIcon.ContextMenu.MenuItems.Add(exitItem);

            this.notifyIcon.DoubleClick += new EventHandler(this.notifyIcon_DoubleClick);
        }

        private void CheckTrayIcon()
        {
            this.ShowTrayIcon(!IsVisible);
        }

        private void ShowTrayIcon(bool show)
        {
            if (this.notifyIcon != null)
                this.notifyIcon.Visible = show;
        }

        private void StartServices()
        {
            string baseAddress = string.Format("net.tcp://{0}:{1}/WcgService", Environment.MachineName, Settings.Default.PortNumber);
            this.wcgServiceHost = new ServiceHost(typeof(WcfCGServices.Library.WCGService), new Uri(baseAddress));
            ServiceEndpoint endpoint = this.wcgServiceHost.AddServiceEndpoint(
                typeof(WcfCGServices.Contracts.Messages.IWCGService),
                new NetTcpBinding { MaxReceivedMessageSize = Settings.Default.MaxReceivedMessageSize, TransferMode = TransferMode.Streamed },
                "");
            this.wcgServiceHost.Description.Behaviors.Clear();
            this.wcgServiceHost.Description.Behaviors.Add(
                new ServiceBehaviorAttribute
                {
                    UseSynchronizationContext = false,
                    ConcurrencyMode = System.ServiceModel.ConcurrencyMode.Multiple,
                    IncludeExceptionDetailInFaults = true
                });
            this.CreateCallLogger();

            endpoint.Behaviors.Add(new CallLoggingEndpointBehavior(this.callLogger));

            this.wcgServiceHost.Open();
        }

        private void StopServices()
        {
            if (this.wcgServiceHost != null)
            {
                this.wcgServiceHost.Close();
                this.wcgServiceHost = null;
            }
            if (this.callLogger != null)
            {
                this.callLogger.Busy -= new EventHandler(this.OnCallLoggerBusy);
                this.callLogger.Idle -= new EventHandler(this.OnCallLoggerIdle);
                this.callLogger = null;
            }
        }

        private void CreateCallLogger()
        {
            this.callLogger = new CallLogger();
            this.callLogger.Busy += new EventHandler(this.OnCallLoggerBusy);
            this.callLogger.Idle += new EventHandler(this.OnCallLoggerIdle);
        }

        private void CloseApplication()
        {
            this.isClosing = true;
            this.Close();
        }

        private void ShowUI()
        {
            this.Show();
            this.WindowState = this.storedWindowState;
            this.Activate();
        }

        private void ShowStatusImage(string imageUri)
        {
            BitmapImage imageSource = new BitmapImage(new Uri(imageUri));
            this.imgProgress.Source = imageSource;
        }

        #endregion

        #region Event handlers

        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            this.CloseApplication();
        }

        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            this.ShowUI();
        }

        private void OnStateChanged(object sender, EventArgs e)
        {
            if (this.WindowState == WindowState.Minimized)
            {
                this.Hide();
                //if (this.notifyIcon != null)
                //    this.notifyIcon.ShowBalloonTip(2000);
            }
            else
                this.storedWindowState = this.WindowState;
        }

        private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            this.CheckTrayIcon();
        }

        private void OnCallLoggerIdle(object sender, EventArgs e)
        {
            this.Dispatcher.Invoke(new Action(() =>
                {
                    this.txtMessage.Text = "Idle";
                    this.notifyIcon.Icon = new System.Drawing.Icon(
                        Assembly.GetExecutingAssembly().GetManifestResourceStream("WcfCGServicesHost.appIconIdle.ico"));
                
                    this.ShowStatusImage(MainWindow.IdleImageUri);
                    Storyboard storyboard = this.Resources["progressStoryboard"] as Storyboard;
                    storyboard.Stop();
                }));
        }

        private void OnCallLoggerBusy(object sender, EventArgs e)
        {
            this.Dispatcher.Invoke(new Action(() =>
            {
                this.txtMessage.Text = "Busy";
                this.notifyIcon.Icon = new System.Drawing.Icon(
                    Assembly.GetExecutingAssembly().GetManifestResourceStream("WcfCGServicesHost.appIconBusy.ico"));

                this.ShowStatusImage(MainWindow.ProgressImageUri);
                Storyboard storyboard = this.Resources["progressStoryboard"] as Storyboard;
                storyboard.Begin();
                this.imgProgressTransform.Angle = 0;
            }));
        }

        private void OnContextMenuOpen(object sender, EventArgs e)
        {
            this.ShowUI();
        }

        private void OnContextMenuExit(object sender, EventArgs e)
        {
            this.CloseApplication();
        }

        #endregion
    }
}
